home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-wos-src / vlink / main.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  13KB  |  451 lines

  1. /* $VER: vlink main.c V0.6 (24.10.98)
  2.  *
  3.  * This file is part of vlink, a portable linker for multiple
  4.  * object formats.
  5.  * Copyright (c) 1997-99  Frank Wille
  6.  *
  7.  * vlink is freeware and part of the portable and retargetable ANSI C
  8.  * compiler vbcc, copyright (c) 1995-99 by Volker Barthelmann.
  9.  * vlink may be freely redistributed as long as no modifications are
  10.  * made and nothing is charged for it. Non-commercial usage is allowed
  11.  * without any restrictions.
  12.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  13.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  14.  *
  15.  *
  16.  * v0.6  (24.10.98) phx
  17.  *       -baseoff will modify the base-reg section offset for the
  18.  *       destination target.
  19.  *       Deleted obsolete make_baserel_offsets().
  20.  * v0.5d (22.08.98) phx
  21.  *       Faster memory allocation can be activated by #define FASTALLOC.
  22.  * v0.5  (27.06.98) phx
  23.  *       -v shows default target.
  24.  * v0.4  (05.06.98) phx
  25.  *       -sc forces merging of all code sections in an executable.
  26.  *       -sd forces merging of all data and bss sections in an executable.
  27.  *       -multibase prevents auto-merging of sections, which are accessed
  28.  *       base-relative.
  29.  *       Call linker_relrefs() to find all relative references between
  30.  *       sections.
  31.  * v0.3  (16.04.98) phx
  32.  *       -R directs vlink to generate short relocs, if the target format
  33.  *       allows this. It is for example supported by ELF and AmigaDos.
  34.  *       New option -F for reading a list of input files.
  35.  * v0.2  (07.03.98) phx
  36.  *       -v shows standard library path.
  37.  * v0.1  (27.02.98) phx
  38.  *       First version that seems to link AmigaOS ADOS and EHF
  39.  *       objects and libraries. Many common features, like linking
  40.  *       sections together which have relative references, are
  41.  *       still missing. Also, PowerPC-ELF32 support is about to come.
  42.  * v0.0  (04.08.97) phx
  43.  *       File created. Project started on a beautiful summer-day
  44.  *       at the North Sea beach of Cuxhaven. :)
  45.  */
  46.  
  47.  
  48. #define MAIN_C
  49. #include "vlink.h"
  50.  
  51.  
  52. struct GlobalVars gvars;
  53.  
  54.  
  55. void cleanup(struct GlobalVars *);
  56.  
  57. static char *get_option_arg(int,char *[],int *);
  58. static void ReadListFile(struct GlobalVars *,char *);
  59.  
  60.  
  61.  
  62. main(int argc,char *argv[])
  63. {
  64.   struct GlobalVars *gv = &gvars;
  65.   int i,j;
  66.   char *buf;
  67.   struct LibPath *libp;
  68.   struct InputFile *ifn;
  69.   bool stdlib;
  70.   bool dynamic = TRUE;  /* link with dynamic libraries first */
  71.   int so_version = 0;   /* minum version for shared objects */
  72.  
  73. #ifdef FASTALLOC
  74.   init_mem();
  75. #endif
  76.   /* initialize and set default values */
  77.   memset(gv,0,sizeof(struct GlobalVars));
  78.   initlist(&gv->libpaths);
  79.  
  80. #ifdef LIBPATH
  81.   libp = alloc(sizeof(struct LibPath));
  82.   libp->path = LIBPATH;  /* default search path */
  83.   addtail(&gv->libpaths,&libp->n);
  84.   stdlib = TRUE;
  85. #else
  86.   stdlib = FALSE;
  87. #endif
  88.  
  89. #ifdef DEFTARGET
  90.   for (j=0; fff[j]; j++) {
  91.     if (!strcmp(fff[j]->tname,DEFTARGET)) {
  92.       gv->dest_format = (uint8)j;
  93.       break;
  94.     }
  95.   }
  96.   if (fff[j] == NULL) {
  97.     fprintf(stderr,"Configuration warning: Selected default target "
  98.             "\"%s\" is not included.\nThe current default target "
  99.             "is \"%s\".\n",DEFTARGET,fff[gv->dest_format]->tname);
  100.     printf("\n");
  101.   }
  102. #endif
  103.  
  104.   initlist(&gv->inputlist);
  105.   initlist(&gv->lnksec);
  106.   gv->dest_name = "a.out";
  107.   gv->maxerrors = DEF_MAXERRORS;
  108.  
  109.   if (argc<2 || (argc==2 && *argv[1]=='?')) {
  110.     show_usage();
  111.     exit(EXIT_SUCCESS);
  112.   }
  113.  
  114.   for (i=1; i<argc; i++) {
  115.  
  116.     if (*argv[i] == '-') {  /* option detected */
  117.       switch (argv[i][1]) {
  118.  
  119.         case 'b':  
  120.           if (!strcmp(&argv[i][2],"aseoff")) {  /* set base-relative offset */
  121.             ++i;
  122.             if (i<argc && *argv[i]!='-') {
  123.               long bo;
  124.               sscanf(argv[i],"%li",&bo);
  125.               fff[gv->dest_format]->baseoff = bo;
  126.             }
  127.             else
  128.               error(34,argv[--i]);  /* option requires argument */
  129.           }
  130.  
  131.           else {  /* select target format */
  132.             if (buf = get_option_arg(argc,argv,&i)) {
  133.               for (j=0; fff[j]; j++)
  134.                 if (!strcmp(fff[j]->tname,buf))
  135.                   break;
  136.               if (fff[j])
  137.                 gv->dest_format = (uint8)j;
  138.               else
  139.                 error(9,buf);  /* invalid target format */
  140.             }
  141.             else
  142.               error(5,'b');  /* option requires argument */
  143.           }
  144.           break;
  145.  
  146.         case 'd':
  147.           if (buf = get_option_arg(argc,argv,&i)) {
  148.             switch (*buf) {
  149.               case 'n':  /* static */
  150.                 dynamic = FALSE;
  151.                 break;
  152.               case 'y':  /* dynamic */
  153.                 dynamic = TRUE;
  154.                 break;
  155.               case 'c':
  156.                 gv->alloc_common = TRUE;  /* force alloc. of common syms. */
  157.                 break;
  158.               case 'p':
  159.                 /* @@@ something with procedures... don't know */
  160.                 break;
  161.               default:
  162.                 error(4,*buf);  /* unknown argument for option -d */
  163.                 break;
  164.             }
  165.           }
  166.           else
  167.             error(5,'d');  /* option requires argument */
  168.           break;
  169.  
  170.         case 'h':  /* help text */
  171.           show_usage();
  172.           exit(EXIT_SUCCESS);
  173.  
  174.         case 'l':  /* library specifier */
  175.           if (buf = get_option_arg(argc,argv,&i)) {
  176.             ifn = alloc(sizeof(struct InputFile));
  177.             ifn->name = buf;
  178.             ifn->lib = TRUE;
  179.             ifn->dynamic = dynamic;
  180.             ifn->so_ver = so_version;
  181.             so_version = 0;
  182.             addtail(&gv->inputlist,&ifn->n);
  183.           }
  184.           else
  185.             error(5,'l');  /* option requires argument */
  186.           break;
  187.  
  188.         case 'm':
  189.           if (!strcmp(&argv[i][2],"ultibase"))
  190.             gv->multibase = TRUE;
  191.           else
  192.             error(2,argv[i]);  /* unrecognized option */
  193.           break;
  194.  
  195.         case 'n':
  196.           if (!strcmp(&argv[i][2],"ostdlib")) {
  197.             if (stdlib) {
  198.               remhead(&gv->libpaths);
  199.               stdlib = FALSE;
  200.             }
  201.           }
  202.           else
  203.             error(2,argv[i]);  /* unrecognized option */
  204.           break;
  205.  
  206.         case 'o':  /* set output file name */
  207.           if (!(gv->dest_name = get_option_arg(argc,argv,&i)))
  208.             error(5,'o');  /* option requires argument */
  209.           break;
  210.  
  211.         case 'r':  /* output is an relocatable object again */
  212.           gv->dest_object = TRUE;
  213.           break;
  214.  
  215.         case 's':
  216.           switch (argv[i][2]) {
  217.             case '\0':  /* strip all symbols */
  218.               gv->strip_symbols = STRIP_ALL;
  219.               break;
  220.             case 'c':   /* -sc force small code */
  221.               gv->small_code = TRUE;
  222.               break;
  223.             case 'd':   /* -d force small data */
  224.               gv->small_code = TRUE;
  225.               break;
  226.             case 't':   /* -static */
  227.               dynamic = FALSE;
  228.               break;
  229.             default:
  230.               error(2,argv[i]);  /* unrecognized option */
  231.               break;
  232.           }
  233.           break;
  234.  
  235.         case 't':  /* trace file accesses */
  236.           gv->trace_file = stderr;
  237.           break;
  238.  
  239.         case 'u':  /* mark symbol as undefined */
  240.           /* @@@ ... */
  241.           break;
  242.  
  243.         case 'v':  /* show version and target info */
  244.           show_version();
  245.           printf("Standard library path: %s\nDefault target: %s\n"
  246.                  "Supported targets:", stdlib ? 
  247.                  ((struct LibPath *)(gv->libpaths.first))->path : "none",
  248.                  fff[gv->dest_format]->tname);
  249.           for (j=0; fff[j]; j++)
  250.             printf(" %s",fff[j]->tname);
  251.           printf("\n");
  252.           exit(EXIT_SUCCESS);
  253.  
  254.         case 'w':  /* suppress warnings */
  255.           gv->dontwarn = TRUE;
  256.           break;
  257.  
  258.         case 'x':  /* discard all local symbols */
  259.           gv->discard_local = DISLOC_ALL;
  260.           break;
  261.  
  262.         case 'y':  /* trace all accesses on a specific symbol */
  263.           if (gv->trace_syms == NULL)
  264.             gv->trace_syms = alloc_hashtable(TRSYMHTABSIZE);
  265.           if (buf = get_option_arg(argc,argv,&i)) {
  266.             struct SymNames **chain = 
  267.                             &gv->trace_syms[elf_hash(buf)%TRSYMHTABSIZE];
  268.             while (*chain)
  269.               chain = &(*chain)->next;
  270.             *chain = alloczero(sizeof(struct SymNames));
  271.             (*chain)->name = buf;
  272.           }
  273.           else
  274.             error(5,'y');  /* option requires argument */
  275.           break;
  276.  
  277.         case 'B':  /* set link mode */
  278.           if (buf = get_option_arg(argc,argv,&i)) {
  279.             if (!strcmp(buf,"static")) {
  280.               dynamic = FALSE;
  281.             }
  282.             else if (!strcmp(buf,"dynamic")) {
  283.               dynamic = TRUE;
  284.             }
  285.             else if (!strcmp(buf,"shareable")) {
  286.               gv->dest_object = TRUE;
  287.               gv->dest_sharedobj = TRUE;
  288.             }
  289.             else if (!strcmp(buf,"forcearchive")) {
  290.               gv->whole_archive = TRUE;
  291.             }
  292.             else if (!strcmp(buf,"symbolic")) {
  293.               ;  /* don't know, what this means... */
  294.             }
  295.             else {
  296.               error(3,buf);  /* unknown link mode */
  297.             }
  298.           }
  299.           else
  300.             error(5,'B');  /* option requires argument */
  301.           break;
  302.  
  303.         case 'F':  /* read a file with object file names */
  304.           if (buf = get_option_arg(argc,argv,&i))
  305.             ReadListFile(gv,buf);
  306.           else
  307.             error(5,'F');  /* option requires argument */
  308.           break;
  309.  
  310.         case 'L':  /* new library search path */
  311.           if (buf = get_option_arg(argc,argv,&i)) {
  312.             libp = alloc(sizeof(struct LibPath));
  313.             libp->path = buf;
  314.             addtail(&gv->libpaths,&libp->n);
  315.           }
  316.           else
  317.             error(5,'L');  /* option requires argument */
  318.           break;
  319.  
  320.         case 'M':  /* mapping output */
  321.           gv->map_file = stdout;
  322.           break;
  323.  
  324.         case 'R':  /* use short form for relocations */
  325.           gv->short_rel = TRUE;
  326.           break;
  327.  
  328.         case 'S':  /* strip debugger symbols */
  329.           gv->strip_symbols = STRIP_DEBUG;
  330.           break;
  331.  
  332.         case 'T':  /* define base address of a section */
  333.           if (buf = get_option_arg(argc,argv,&i)) {
  334.             if (++i < argc) {
  335.               struct SecBase *sb = alloczero(sizeof(struct SecBase));
  336.               struct SecBase *p = (struct SecBase *)&gv->secbases;
  337.  
  338.               sb->name = buf;
  339.               sscanf(argv[i],"%li",(long *)&sb->base); /* set base address */              
  340.               while (p->next)
  341.                 p = p->next;
  342.               p->next = sb;
  343.             }
  344.           }
  345.           error(5,'T');  /* option requires argument */
  346.           break;
  347.  
  348.         case 'V':  /* set minimum version for next shared object */
  349.           if (buf = get_option_arg(argc,argv,&i))
  350.             so_version = atoi(buf);
  351.           else
  352.             error(5,'V');  /* option requires argument */
  353.           break;
  354.  
  355.         case 'X':  /* discard temporary local symbols only */
  356.           gv->discard_local = DISLOC_TMP;
  357.           break;
  358.  
  359.         default:
  360.           error(2,argv[i]);  /* unrecognized option */
  361.           break;
  362.       }
  363.     }
  364.  
  365.     else {  /* normal input file name */
  366.       ifn = alloc(sizeof(struct InputFile));
  367.       ifn->name = argv[i];
  368.       ifn->lib = FALSE;
  369.       addtail(&gv->inputlist,&ifn->n);
  370.     }
  371.   }
  372.  
  373.   if (listempty(&gv->inputlist))
  374.     error(6);  /* no input files */
  375.  
  376.   /* link them... */
  377.   linker_init(gv);
  378.   linker_load(gv);     /* load all objects and libraries and their symbols */
  379.   linker_resolve(gv);  /* resolve symbol references */
  380.   linker_relrefs(gv);  /* find all relative references between sections */
  381.   linker_join(gv);     /* join sections with same name and type */
  382.   linker_copy(gv);     /* copy section contents and fix symbol offsets */
  383.   linker_relocate(gv); /* relocate addresses in joined sections */
  384.   linker_write(gv);    /* write output file in selected target format */
  385.   linker_cleanup(gv);
  386.  
  387.   cleanup(gv);
  388. }
  389.  
  390.  
  391. static char *get_option_arg(int argc,char *argv[],int *i)
  392. /* get pointer to the string, which either directly follows the option
  393.    character or is stored in the next argument */
  394. {
  395.   if (argv[*i][2])
  396.     return (&argv[*i][2]);
  397.   else {
  398.     if (++*i<argc) {
  399.       if (argv[*i][0]!='-' || isdigit(argv[*i][1]))  /* another option? */
  400.         return (argv[*i]);
  401.       else
  402.         --*i;
  403.     }
  404.   }
  405.   return NULL;
  406. }
  407.  
  408.  
  409. static void  ReadListFile(struct GlobalVars *gv,char *name)
  410. /* read a file, which contains a list of object file names */
  411. {
  412.   FILE *f;
  413.   struct InputFile *ifn;
  414.   char buf[256],c,*p,*n=NULL;
  415.  
  416.   if (f = fopen(name,"r")) {
  417.     while (fgets(buf,255,f)) {
  418.       p = buf;
  419.       do {
  420.         c = *p++;
  421.         if (c=='\"') {  /* read file name in quotes */
  422.           n = p;
  423.           while (*p && *p!='\"')
  424.             ++p;
  425.           c = *p++ ? 1:0;
  426.         }
  427.         else if (c>' ' && !n)
  428.           n = p-1;  /* new file name */
  429.         if (c<=' ' && n) {  /* file name ends here */
  430.           *(p-1) = 0;
  431.           ifn = alloc(sizeof(struct InputFile));
  432.           ifn->name = allocstring(n);
  433.           ifn->lib = FALSE;
  434.           addtail(&gv->inputlist,&ifn->n);
  435.           n = NULL;
  436.         }
  437.       }
  438.       while (c);
  439.     }
  440.     fclose(f);
  441.   }
  442.   else
  443.     error(8,name);  /* cannot open */
  444. }
  445.  
  446.  
  447. void cleanup(struct GlobalVars *gv)
  448. {
  449.   exit(gv->returncode);
  450. }
  451.